package generator;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.converts.SqliteTypeConvert;
import com.baomidou.mybatisplus.generator.config.querys.SqliteQuery;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.Scanner;

/**
 * mybatis-plus代码生成器，生成实体，mapper，mapper.xml，service，serviceImpl，controller
 * 演示例子，执行 main 方法控制台输入表名回车自动生成对应项目目录中(目录要需要自行修改)
 */
public class CodeGenerator {

    public static String URL = "jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8";
    public static String USERNAME = "root";
    public static String PASSWORD = "admin";

    public static String SUPPER_MAPPER_CLASS = "com.baomidou.mybatisplus.core.mapper.BaseMapper";
    public static String BASE_PACKAGE = "top.wyz5204";
    public static String ENTITY_PACKAGE = "domain";
    public static String MAPPER_PACKAGE = "mapper";
    public static String SERVICE_PACKAGE = "service";
    public static String SERVICE_IMPL_PACKAGE = SERVICE_PACKAGE + ".impl";
    public static String CONTROLLER_PACKAGE = "controller";
    public static String PROJECT_PATH = System.getProperty("user.dir");
    public static String MAPPER_OUT_PATH = PROJECT_PATH + "/src/main/resources/mapper";
    public static String PROJECT_RESOURCE_PATH = PROJECT_PATH + "/src/main/java";

    public static String AUTHOR = "top.wyz5204";

    /**
     * 这是一个 mybatisplus的基于数据库的表生成对应的类和dao的方法,省去人工去生成
     * @param args
     */
    public static void main(String[] args) {
        // 用于基于MYSQL数据库的生成java对应的类
//        generateMySQL();
        // 用于基于SQLite数据库的生成java对应的类
        generateSQLite();
    }

    /**
     * 生成代码
     */
    private static void generateMySQL() {
        AutoGenerator autoGenerator = new AutoGenerator(dataSourceConfig())
                .injection(injectionConfig())
                .strategy(strategyConfig())
                .packageInfo(packageInfo())
                .template(templateConfig())
                .global(globalConfig());
        autoGenerator.execute();
    }

    private static void generateSQLite() {
        DataSourceConfig build = new DataSourceConfig.Builder("jdbc:sqlite:D:\\app_java_web\\spring\\db\\test.db", "", "")
                .dbQuery(new SqliteQuery())
//                .schema("main")
                .typeConvert(new SqliteTypeConvert())
                .build();

        AutoGenerator autoGenerator = new AutoGenerator(build)
                .injection(injectionConfig())
                .strategy(strategyConfig())
                .packageInfo(packageInfo())
                .template(templateConfig())
                .global(globalConfig());
        autoGenerator.execute();
    }

    /**
     * 策略配置(StrategyConfig)
     *
     * @return
     */
    private static StrategyConfig strategyConfig() {
        return new StrategyConfig.Builder()
//                .enableSchema() //默认值:false，多 schema 场景的时候打开
                .enableCapitalMode()
                .enableSkipView()
                .disableSqlFilter()
                .addInclude(scanner("表名，多个以逗号分开：").split(","))
                .addTablePrefix("tb_", "t_")
//                .addFieldSuffix("_flag")
//                .likeTable(new LikeTable("USER"))
                .build()
                // Mapper 策略配置
                .mapperBuilder().enableFileOverride()
                .superClass(SUPPER_MAPPER_CLASS)
                .enableMapperAnnotation()
                .enableBaseResultMap()
                .enableBaseColumnList()
                .formatMapperFileName("%sMapper")
                .build()
                // Entity 策略配置
                .entityBuilder().enableFileOverride()
                .enableChainModel()
                .enableLombok()
//                .enableRemoveIsPrefix()
                .enableTableFieldAnnotation()
                .enableActiveRecord()
                .versionColumnName("version")
                .versionPropertyName("version")
                .logicDeleteColumnName("deleted")
                .logicDeletePropertyName("deleteFlag")
                .naming(NamingStrategy.underline_to_camel)
                .columnNaming(NamingStrategy.underline_to_camel)
//                .addSuperEntityColumns("id", "created_by", "created_time", "updated_by", "updated_time")
//                .addIgnoreColumns("age")
//                .addTableFills(new Column("create_time", FieldFill.INSERT))
//                .addTableFills(new Property("updateTime", FieldFill.INSERT_UPDATE))
                .idType(IdType.AUTO)
//                .formatFileName("%sEntity")
                .build()
                // Service 策略配置
                .serviceBuilder().enableFileOverride()
                .formatServiceFileName("%sService")
                .formatServiceImplFileName("%sServiceImpl")
                .build()
                // Controller 策略配置
                .controllerBuilder().enableFileOverride()
                .enableRestStyle()
                .build();
    }

    /**
     * 数据库配置(DataSourceConfig)
     *
     * @return
     */
    private static DataSourceConfig dataSourceConfig() {
        return new DataSourceConfig.Builder(URL, USERNAME, PASSWORD)
                .typeConvert(new MySqlTypeConvert())
                .build();
    }

    /**
     * 注入配置(InjectionConfig)
     *
     * @return
     */
    private static InjectionConfig injectionConfig() {
        return new InjectionConfig.Builder()
                .beforeOutputFile((tableInfo, objectMap) -> {
                    System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size());
                })
//                .customMap(Collections.singletonMap("test", "baomidou"))
//                .customFile(Collections.singletonMap("test.txt", "/templates/test.vm"))
                .build();
    }

    /**
     * 全局配置(GlobalConfig)
     *
     * @param
     */
    private static GlobalConfig globalConfig() {
        return new GlobalConfig.Builder()
                .fileOverride()
                .outputDir(PROJECT_RESOURCE_PATH)
                .author(AUTHOR)
                .disableOpenDir()
//                .enableKotlin()
//                .enableSwagger()
                .dateType(DateType.TIME_PACK)
                .commentDate("yyyy-MM-dd HH:ss")
                .build();
    }

    /**
     * 包配置(PackageConfig)
     *
     * @return
     */
    private static PackageConfig packageInfo() {
        return new PackageConfig.Builder()
                .parent(BASE_PACKAGE)
                // BASE_PACKAGE 这个包后面再添加的包名
//                .moduleName("test")
                .entity(ENTITY_PACKAGE)
                .service(SERVICE_PACKAGE)
                .serviceImpl(SERVICE_IMPL_PACKAGE)
                .mapper(MAPPER_PACKAGE)
                .controller(CONTROLLER_PACKAGE)
                .pathInfo(Collections.singletonMap(OutputFile.xml, MAPPER_OUT_PATH))
                .build();
    }

    /**
     * 模板配置(TemplateConfig)
     *
     * @return
     */
    private static TemplateConfig templateConfig() {
        return new TemplateConfig.Builder()
                .entity("/templates/entity.java")
                .service("/templates/service.java")
                .serviceImpl("/templates/serviceImpl.java")
                .mapper("/templates/mapper.java")
                .xml("/templates/mapper.xml")
                // disable 和 注释掉 controller 就不会生成 Controller类
//                .disable(TemplateType.CONTROLLER)
                .controller("/templates/controller.java")
                .build();
    }


    /**
     * 手动输入需要生成文件的表
     *
     * @param tip
     * @return
     */
    private static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + "：");
        System.out.println(help);
        if (scanner.hasNext()) {
            String input = scanner.next();
            if (StringUtils.isNotEmpty(input)) {
                return input;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }
}



